home *** CD-ROM | disk | FTP | other *** search
/ Programmer Power Tools / Programmer Power Tools.iso / progjrn / pj_7_3a.arc / EVGALINE.C < prev    next >
Text File  |  1989-02-05  |  7KB  |  194 lines

  1. /*
  2.  * *** Listing 1 ***
  3.  *
  4.  * Turbo C implementation of Bresenham's line drawing algorithm
  5.  * for the EGA and VGA. Works in modes 0xE, 0xF, 0x10, and 0x12.
  6.  *
  7.  * Compiled with Turbo C 2.0.
  8.  *
  9.  * By Michael Abrash.  2/4/89.
  10.  */
  11. #include <dos.h>     /* contains MK_FP macro */
  12.  
  13. #define EVGA_SCREEN_WIDTH_IN_BYTES     80
  14.                                        /* memory offset from start of
  15.                                           one row to start of next */
  16. #define EVGA_SCREEN_SEGMENT            0xA000
  17.                                        /* display memory segment */
  18. #define GC_INDEX                       0x3CE
  19.                                        /* Graphics Controller
  20.                                           Index register port */
  21. #define GC_DATA                        0x3CF
  22.                                        /* Graphics Controller
  23.                                           Data register port */
  24. #define SET_RESET_INDEX                0  /* indexes of needed */
  25. #define ENABLE_SET_RESET_INDEX         1  /* Graphics Controller */
  26. #define BIT_MASK_INDEX                 8  /* registers */
  27.  
  28. /*
  29.  * Draws a dot at (X0,Y0) in whatever color the EGA/VGA hardware is
  30.  * set up for. Leaves the bit mask set to whatever value the
  31.  * dot required.
  32.  */
  33. void EVGADot(X0, Y0)
  34. unsigned int X0;     /* coordinates at which to draw dot, with */
  35. unsigned int Y0;     /* (0,0) at the upper left of the screen */
  36. {
  37.    unsigned char far *PixelBytePtr;
  38.    unsigned char PixelMask;
  39.  
  40.    /* Calculate the offset in the screen segment of the byte in
  41.       which the pixel lies */
  42.    PixelBytePtr = MK_FP(EVGA_SCREEN_SEGMENT,
  43.       ( Y0 * EVGA_SCREEN_WIDTH_IN_BYTES ) + ( X0 / 8 ));
  44.  
  45.    /* Generate a mask with a 1 bit in the pixel's position within the
  46.       screen byte */
  47.    PixelMask = 0x80 >> ( X0 & 0x07 );
  48.  
  49.    /* Set up the Graphics Controller's Bit Mask register to allow
  50.       only the bit corresponding to the pixel being drawn to
  51.       be modified */
  52.    outportb(GC_INDEX, BIT_MASK_INDEX);
  53.    outportb(GC_DATA, PixelMask);
  54.  
  55.    /* Draw the pixel. Because of the operation of the set/reset
  56.       feature of the EGA/VGA, the value written doesn't matter.
  57.       The screen byte is ORed in order to perform a read to latch the
  58.       display memory, then perform a write in order to modify it. */
  59.    *PixelBytePtr |= 0xFF;
  60. }
  61.  
  62. /*
  63.  * Draws a line in octant 0 or 3 ( |DeltaX| >= DeltaY ).
  64.  * |DeltaX|+1 points are drawn.
  65.  */
  66. void Octant0(X0, Y0, DeltaX, DeltaY, XDirection)
  67. unsigned int X0, Y0;          /* coordinates of start of the line */
  68. unsigned int DeltaX, DeltaY;  /* length of the line */
  69. int XDirection;               /* 1 if line is drawn left to right,
  70.                                  -1 if drawn right to left */
  71. {
  72.    int DeltaYx2;
  73.    int DeltaYx2MinusDeltaXx2;
  74.    int ErrorTerm;
  75.  
  76.    /* Set up initial error term and values used inside drawing loop */
  77.    DeltaYx2 = DeltaY * 2;
  78.    DeltaYx2MinusDeltaXx2 = DeltaYx2 - (int) ( DeltaX * 2 );
  79.    ErrorTerm = DeltaYx2 - (int) DeltaX;
  80.  
  81.    /* Draw the line */
  82.    EVGADot(X0, Y0);              /* draw the first pixel */
  83.    while ( DeltaX-- ) {
  84.       /* See if it's time to advance the Y coordinate */
  85.       if ( ErrorTerm >= 0 ) {
  86.          /* Advance the Y coordinate & adjust the error term
  87.             back down */
  88.          Y0++;
  89.          ErrorTerm += DeltaYx2MinusDeltaXx2;
  90.       } else {
  91.          /* Add to the error term */
  92.          ErrorTerm += DeltaYx2;
  93.       }
  94.       X0 += XDirection;          /* advance the X coordinate */
  95.       EVGADot(X0, Y0);           /* draw a pixel */
  96.    }
  97. }
  98.  
  99. /*
  100.  * Draws a line in octant 1 or 2 ( |DeltaX| < DeltaY ).
  101.  * |DeltaY|+1 points are drawn.
  102.  */
  103. void Octant1(X0, Y0, DeltaX, DeltaY, XDirection)
  104. unsigned int X0, Y0;          /* coordinates of start of the line */
  105. unsigned int DeltaX, DeltaY;  /* length of the line */
  106. int XDirection;               /* 1 if line is drawn left to right,
  107.                                  -1 if drawn right to left */
  108. {
  109.    int DeltaXx2;
  110.    int DeltaXx2MinusDeltaYx2;
  111.    int ErrorTerm;
  112.  
  113.    /* Set up initial error term and values used inside drawing loop */
  114.    DeltaXx2 = DeltaX * 2;
  115.    DeltaXx2MinusDeltaYx2 = DeltaXx2 - (int) ( DeltaY * 2 );
  116.    ErrorTerm = DeltaXx2 - (int) DeltaY;
  117.  
  118.    EVGADot(X0, Y0);           /* draw the first pixel */
  119.    while ( DeltaY-- ) {
  120.       /* See if it's time to advance the X coordinate */
  121.       if ( ErrorTerm >= 0 ) {
  122.          /* Advance the X coordinate & adjust the error term
  123.             back down */
  124.          X0 += XDirection;
  125.          ErrorTerm += DeltaXx2MinusDeltaYx2;
  126.       } else {
  127.          /* Add to the error term */
  128.          ErrorTerm += DeltaXx2;
  129.       }
  130.       Y0++;                   /* advance the Y coordinate */
  131.       EVGADot(X0, Y0);        /* draw a pixel */
  132.    }
  133. }
  134.  
  135. /*
  136.  * Draws a line on the EGA or VGA.
  137.  */
  138. void EVGALine(X0, Y0, X1, Y1, Color)
  139. int X0, Y0;    /* coordinates of one end of the line */
  140. int X1, Y1;    /* coordinates of the other end of the line */
  141. char Color;    /* color to draw line in */
  142. {
  143.    int DeltaX, DeltaY;
  144.    int Temp;
  145.  
  146.    /* Set the drawing color */
  147.  
  148.    /* Put the drawing color in the Set/Reset register */
  149.    outportb(GC_INDEX, SET_RESET_INDEX);
  150.    outportb(GC_DATA, Color);
  151.    /* Cause all planes to be forced to the Set/Reset color */
  152.    outportb(GC_INDEX, ENABLE_SET_RESET_INDEX);
  153.    outportb(GC_DATA, 0xF);
  154.  
  155.    /* Save half the line-drawing cases by swapping Y0 with Y1
  156.       and X0 with X1 if Y0 is greater than Y1. As a result, DeltaY
  157.       is always > 0, and only the octant 0-3 cases need to be
  158.       handled. */
  159.    if ( Y0 > Y1 ) {
  160.       Temp = Y0;
  161.       Y0 = Y1;
  162.       Y1 = Temp;
  163.       Temp = X0;
  164.       X0 = X1;
  165.       X1 = Temp;
  166.    }
  167.  
  168.    /* Handle as four separate cases, for the four octants in which
  169.       Y1 is greater than Y0 */
  170.    DeltaX = X1 - X0;    /* calculate the length of the line
  171.                            in each coordinate */
  172.    DeltaY = Y1 - Y0;
  173.    if ( DeltaX > 0 ) {
  174.       if ( DeltaX > DeltaY ) {
  175.          Octant0(X0, Y0, DeltaX, DeltaY, 1);
  176.       } else {
  177.          Octant1(X0, Y0, DeltaX, DeltaY, 1);
  178.       }
  179.    } else {
  180.       DeltaX = -DeltaX;             /* absolute value of DeltaX */
  181.       if ( DeltaX > DeltaY ) {
  182.          Octant0(X0, Y0, DeltaX, DeltaY, -1);
  183.       } else {
  184.          Octant1(X0, Y0, DeltaX, DeltaY, -1);
  185.       }
  186.    }
  187.  
  188.    /* Return the state of the EGA/VGA to normal */
  189.    outportb(GC_INDEX, ENABLE_SET_RESET_INDEX);
  190.    outportb(GC_DATA, 0);
  191.    outportb(GC_INDEX, BIT_MASK_INDEX);
  192.    outportb(GC_DATA, 0xFF);
  193. }
  194.